package arm_search_3.utilities;

import arm_search_3.data.ResultModelComparator;
import arm_search_3.data.ResultModel;
import arm_search_3.data.Term;
import arm_search_3.data.email.EmailStatistic;
import arm_search_3.data.email.EmailStatistic.EmailDocumentStatistic;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.PriorityQueue;

/**
 *
 * @author Muqtafi Akhmad
 */
public class TermHelper {

    public static Term getTermObject(String indexDirectory, String tokenString, boolean isCompressed) {
        // membaca term dari dalam directory
        Term resultTerm = new Term(tokenString);
        resultTerm.setStatistic(new EmailStatistic(resultTerm.getTermString()));
        File indexDir = new File(indexDirectory);
        File workerFolders[] = indexDir.listFiles();
        for (File workerFolder : workerFolders) {
            if (workerFolder.isDirectory()) {
                // cek apakah ada file index dari term dalam worker
                File checkFile = new File(resultTerm.getPath(workerFolder.getAbsolutePath()));
                if (checkFile.exists()) {
                    // load token
                    Term tempToken = new Term(tokenString);
                    tempToken.loadTerm(checkFile.getAbsolutePath());
                    resultTerm.getStatistic().merge(tempToken.getStatistic());
                }
            }
        }
        return resultTerm;
    }

    public static HashMap<Integer, ArrayList<Integer>> getPostingList(Term term, String field) {
        EmailStatistic stat = (EmailStatistic) term.getStatistic();
        if (field.equals("all")) {
            EmailDocumentStatistic docStat = new EmailDocumentStatistic();
            docStat.merge(stat.getDocStatistic("from"));
            docStat.merge(stat.getDocStatistic("to"));
            docStat.merge(stat.getDocStatistic("subject"));
            docStat.merge(stat.getDocStatistic("date"));
            docStat.merge(stat.getDocStatistic("body"));
            return docStat.getRelatedDocs();
        } else {
            return stat.getDocStatistic(field).getRelatedDocs();
        }
    }

    public static HashMap<Integer, ResultModel> processPostingLists(ArrayList<HashMap<Integer, ArrayList<Integer>>> postingLists, boolean isPhrase) {
        HashMap<Integer, ResultModel> result = new HashMap<>();
        if (postingLists.size() > 0) {
            HashMap<Integer, ArrayList<Integer>> refPostingList = postingLists.get(0);
            if (!isPhrase) {
                // not exact match
                Iterator it = refPostingList.entrySet().iterator();
                int i, matchCount;
                while (it.hasNext()) {
                    Map.Entry pairs = (Map.Entry) it.next();
                    Integer docID = (Integer) pairs.getKey();
                    ArrayList<Integer> postings = (ArrayList<Integer>) pairs.getValue();
                    // cek apakah dari posting referensi muncul juga di posting list yang lain
                    // match count adalah jumlah minimal kemunculan dalam dokumen yang ada
                    matchCount = postings.size();
                    for (i = 1; i < postingLists.size(); i++) {
                        if (!postingLists.get(i).containsKey(docID)) {
                            matchCount = 0;
                            break;
                        } else {
                            int tempMatch = ((ArrayList<Integer>) (postingLists.get(i).get(docID))).size();
                            if (tempMatch < matchCount) {
                                matchCount = tempMatch;
                            }
                        }
                    }
                    if (matchCount > 0) {
                        result.put(docID, new ResultModel(docID, new Integer(matchCount), new Float(new Float(matchCount) / new Float(refPostingList.size()))));
                    }
                }
            } else {
                // exact match
                Iterator it = refPostingList.entrySet().iterator();
                int i, matchCount;
                while (it.hasNext()) {
                    matchCount = 0;
                    Map.Entry pairs = (Map.Entry) it.next();
                    Integer docID = (Integer) pairs.getKey();
                    ArrayList<Integer> postings = (ArrayList<Integer>) pairs.getValue();
                    // cek untuk setiap posting apakah ada sequence di posting list selanjutnya
                    for (Integer posting : postings) {
                        boolean seq = true;
                        for (i = 1; i < postingLists.size(); i++) {
                            HashMap<Integer, ArrayList<Integer>> docPosting = postingLists.get(i);
                            if (docPosting.containsKey(docID)) {
                                if (!((ArrayList<Integer>) docPosting.get(docID)).contains(posting + i)) {
                                    seq = false;
                                    break;
                                }
                            } else {
                                seq = false;
                                break;
                            }
                        }
                        if (seq) {
                            matchCount++;
                        }
                    }
                    if (matchCount > 0) {
                        result.put(docID, new ResultModel(docID, new Integer(matchCount), new Float(new Float(matchCount) / new Float(refPostingList.size()))));
                    }
                }
            }
        }
        return result;
    }

    public static PriorityQueue<ResultModel> processResultModels(ArrayList<HashMap<Integer, ResultModel>> resultModels) {
        if (resultModels.size() > 0) {
            PriorityQueue<ResultModel> result = new PriorityQueue<>(10, new ResultModelComparator());
            HashMap<Integer, ResultModel> ref = resultModels.get(0);
            Iterator it = ref.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry pairs = (Map.Entry) it.next();
                // cek jika dokumen juga muncul di semua hashmap lain, jika muncul tambahkan ke result
                boolean exist = true;
                int i;
                ResultModel model = (ResultModel) pairs.getValue();
                for (i = 1; i < resultModels.size(); i++) {
                    if(resultModels.get(i).containsKey(model.getDocumentID())){
                        // merge dengan model
                        model.merge((ResultModel) resultModels.get(i).get(model.getDocumentID()));
                    }else{
                        exist = false;
                        break;
                    }
                }
                if (exist) {
                    // jika dokumen pada ref muncul pada array model yang lain maka tambahkan ke hasil
                    result.add(model);
                }
            }
            return result;
        }
        return new PriorityQueue<>();
    }
}
